package com.xjrsoft.module.customerTwo.EMP.checkin_log.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.result.Response;
import com.xjrsoft.core.constant.RedisKeyConstants;
import com.xjrsoft.core.tool.utils.CollectionUtil;
import com.xjrsoft.core.tool.utils.StringUtil;
import com.xjrsoft.module.customerTwo.EMP.checkin_log.entity.TElectricCheckinItems;
import com.xjrsoft.module.customerTwo.EMP.checkin_log.entity.TElectricCheckinLog;
import com.xjrsoft.module.customerTwo.EMP.checkin_log.dto.TElectricCheckinLogListDto;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xjrsoft.common.page.ConventPage;

import java.time.LocalDateTime;
import java.util.*;

import com.xjrsoft.module.customerTwo.EMP.checkin_log.mapper.TElectricCheckinLogMapper;
import com.xjrsoft.module.customerTwo.EMP.checkin_log.service.ITElectricCheckinItemsService;
import com.xjrsoft.module.customerTwo.EMP.checkin_log.service.ITElectricCheckinLogService;
import com.xjrsoft.core.mp.base.BaseService;
import com.xjrsoft.core.tool.utils.Func;
import com.xjrsoft.module.customerTwo.EMP.dormitory_room.entity.TDormitoryRoom;
import com.xjrsoft.module.customerTwo.EMP.dormitory_room.service.ITDormitoryRoomService;
import com.xjrsoft.module.customerTwo.EMP.settlement.entity.TElectricCheckoutSettlementTools;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;


/**
 *  服务实现类
 *
 * @author lisen
 * @since 2023-07-21
 */
@Service
@AllArgsConstructor
public class TElectricCheckinLogServiceImpl extends BaseService<TElectricCheckinLogMapper, TElectricCheckinLog> implements ITElectricCheckinLogService {

	private ITElectricCheckinItemsService itElectricCheckinItemsService;
	@Resource
	ITDormitoryRoomService roomService;

	@Resource
	RedisTemplate<String,Object> redisTemplate;

	@Override
	public IPage<TElectricCheckinLog> getPageList(TElectricCheckinLogListDto pageListDto) {
		Wrapper<TElectricCheckinLog> wrapper = Wrappers.<TElectricCheckinLog>query().lambda()
				.like(!StringUtil.isEmpty(pageListDto.getRoom_id()), TElectricCheckinLog::getRoomId, pageListDto.getRoom_id())
				.like(!StringUtil.isEmpty(pageListDto.getIdentify_name()), TElectricCheckinLog::getIdentifyName, pageListDto.getIdentify_name())
				.like(!StringUtil.isEmpty(pageListDto.getIdentify_id()), TElectricCheckinLog::getIdentifyId, pageListDto.getIdentify_id())
				.like(!StringUtil.isEmpty(pageListDto.getDivision()), TElectricCheckinLog::getDivision, pageListDto.getDivision())
				.eq(!StringUtil.isEmpty(pageListDto.getDepartment()), TElectricCheckinLog::getDepartment, pageListDto.getDepartment())
				.like(!StringUtil.isEmpty(pageListDto.getPhone_number()), TElectricCheckinLog::getPhoneNumber, pageListDto.getPhone_number())
				.ge(!StringUtil.isEmpty(pageListDto.getCheckin_date_Start()), TElectricCheckinLog::getCheckinDate, pageListDto.getCheckin_date_Start())
				.le(!StringUtil.isEmpty(pageListDto.getCheckin_date_End()), TElectricCheckinLog::getCheckinDate, pageListDto.getCheckin_date_End())
				.eq(!StringUtil.isEmpty(pageListDto.getIs_couple_room()), TElectricCheckinLog::getIsCoupleRoom, pageListDto.getIs_couple_room())
				.like(!StringUtil.isEmpty(pageListDto.getRoom_number()), TElectricCheckinLog::getRoomNumber, pageListDto.getRoom_number())
				.eq(!StringUtil.isEmpty(pageListDto.getIs_checkout()), TElectricCheckinLog::getIsCheckout, pageListDto.getIs_checkout())
				.like(!StringUtil.isEmpty(pageListDto.getWorkshop()), TElectricCheckinLog::getWorkshop, pageListDto.getWorkshop())
				.eq(!StringUtil.isEmpty(pageListDto.getIslocked()), TElectricCheckinLog::getIslocked, pageListDto.getIslocked())
				.like(!StringUtil.isEmpty(pageListDto.getGender()), TElectricCheckinLog::getGender, pageListDto.getGender())
				.eq(!StringUtil.isEmpty(pageListDto.getIskeyreturned()), TElectricCheckinLog::getIsKeyReturned, pageListDto.getIskeyreturned())
				.eq(!StringUtil.isEmpty(pageListDto.getIslastone()), TElectricCheckinLog::getIsLastOne, pageListDto.getIslastone())

				.ge(!StringUtil.isEmpty(pageListDto.getCheckout_date_Start()), TElectricCheckinLog::getCheckoutDate, pageListDto.getCheckout_date_Start())
				.le(!StringUtil.isEmpty(pageListDto.getCheckout_date_End()), TElectricCheckinLog::getCheckoutDate, pageListDto.getCheckout_date_End());

		return this.page(ConventPage.getPage(pageListDto), wrapper);
	}

	@Override
	public TElectricCheckinLog getInfoById(String id){
		TElectricCheckinLog checkinLog = getById(id);
		TDormitoryRoom room = roomService.getByRoomNumber(checkinLog.getRoomNumber());
		if(room.getUsedBedNumber().equals(1)&& checkinLog.getIsCheckout().equals(0)){
			checkinLog.setIsLastOne(1);
		}
		return checkinLog;
	}
	/**
	* Title: updateRedis
	* @description 更新房间缓存的信息
	* @createTime  2023-12-05 9:32
	* @param
	* @return boolean
	*/
	@Override
	public boolean updateRedis(){
		roomService.getRoomLeft();
		return true;
	}
	/**
	 * Title: 确认
	 * @description
	 * @createTime  2023-07-25 11:09
	 * @param
	 * @return
	 */
	@Override
	public boolean confirm(String id) {
		TElectricCheckinLog tElectricCheckinLog = getById(id);
		if(tElectricCheckinLog.getIslocked()==1){
			tElectricCheckinLog.setIslocked(0);
			return this.updateById(tElectricCheckinLog);
		}
		tElectricCheckinLog.setIslocked(1);
		return this.updateById(tElectricCheckinLog);
	}

	/**
	 * Title: 新增入住登记
	 * @description 登记同时对应房间入住人员加1
	 * @createTime  2023-07-25 11:09
	 * @param
	 * @return
	 */
	@Override
	@Transactional(rollbackFor=Exception.class)
	public boolean add(TElectricCheckinLog tElectricCheckinLog, List<TElectricCheckinItems> tElectricCheckinItemsList) throws Exception {
		ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
		tElectricCheckinLog.setFid(IdWorker.get32UUID());
		tElectricCheckinItemsList.forEach(tElectricCheckinItems->tElectricCheckinItems.setFid(IdWorker.get32UUID()));
		tElectricCheckinItemsList.forEach(tElectricCheckinItems->tElectricCheckinItems.setCheckinId(tElectricCheckinLog.getFid()));
		String roomNum = tElectricCheckinLog.getRoomNumber();
		if(valueOperations.get(RedisKeyConstants.CACHE_ROOM_LEFT+tElectricCheckinLog.getRoomNumber())==null){
			TDormitoryRoom room = roomService.getByRoomNumber(tElectricCheckinLog.getRoomNumber());
			if("4".equals(room.getRoomType())&&room.getUsedBedNumber()<2&&tElectricCheckinLog.getIsCheckout().equals(0)){
				return this.save(tElectricCheckinLog)&&itElectricCheckinItemsService.saveBatch(tElectricCheckinItemsList)&&roomService.upDateUsedRoomByRoomNum(roomNum,1);
			}
		}
		//入宿
		if(Objects.equals(tElectricCheckinLog.getIsCheckout(), 0)){
			//剩余床位>1
			if((Integer)valueOperations.get(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum)>1){
				redisTemplate.opsForValue().decrement(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum);
				//更新同时更新缓存
				return this.save(tElectricCheckinLog)&&itElectricCheckinItemsService.saveBatch(tElectricCheckinItemsList)&&roomService.upDateUsedRoomByRoomNum(roomNum,1);
			}
			//床位刚好是1
			redisTemplate.delete(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum);

			return this.save(tElectricCheckinLog)&&itElectricCheckinItemsService.saveBatch(tElectricCheckinItemsList)&&roomService.upDateUsedRoomByRoomNum(roomNum,1);
		}
		return this.save(tElectricCheckinLog)&&itElectricCheckinItemsService.saveBatch(tElectricCheckinItemsList);
	}
	@Override
	@Transactional(rollbackFor=Exception.class)
	public boolean checkOut(String id, LocalDateTime dateTime) throws Exception {
		TElectricCheckinLog tElectricCheckinLog =  getById(id);
		ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
		TDormitoryRoom room = roomService.getByRoomNumber(tElectricCheckinLog.getRoomNumber());
		if("4".equals(room.getRoomType())&&room.getUsedBedNumber().equals(2)){
			tElectricCheckinLog.setCheckinDate(dateTime);
			tElectricCheckinLog.setIslocked(1);
			return this.updateById(tElectricCheckinLog)&&roomService.upDateUsedRoomByRoomNum(room.getRoomNumber(),-1);
		}
		if(Objects.equals(tElectricCheckinLog.getIsCheckout(), 0)){
			//有床位
			if(valueOperations.get(RedisKeyConstants.CACHE_ROOM_LEFT+tElectricCheckinLog.getRoomNumber())!=null){
				redisTemplate.opsForValue().increment(RedisKeyConstants.CACHE_ROOM_LEFT+tElectricCheckinLog.getRoomNumber());
				tElectricCheckinLog.setIsCheckout(1);
				tElectricCheckinLog.setCheckoutDate(dateTime);
				this.updateById(tElectricCheckinLog);
				return roomService.upDateUsedRoomByRoomNum(tElectricCheckinLog.getRoomNumber(),-1);
			}
			//无床位
			redisTemplate.opsForValue().set(RedisKeyConstants.CACHE_ROOM_LEFT+tElectricCheckinLog.getRoomNumber(),1);
			tElectricCheckinLog.setIsCheckout(1);
			tElectricCheckinLog.setCheckoutDate(dateTime);
			this.updateById(tElectricCheckinLog);
			return roomService.upDateUsedRoomByRoomNum(tElectricCheckinLog.getRoomNumber(),-1);
		}
		return this.updateById(tElectricCheckinLog);
	}

	/**
	 * Title: 更新入住登记
	 * @description 登记退宿对应房间入住人员减1，反之加1
	 * @createTime  2023-07-25 11:09
	 * @param
	 * @return
	 */
	@Override
	@Transactional(rollbackFor=Exception.class)
	public boolean update(String id, TElectricCheckinLog tElectricCheckinLog, List<TElectricCheckinItems> tElectricCheckinItemsList) throws Exception {
		List<String> tElectricCheckinItemsIdList = new ArrayList<>();
		for (TElectricCheckinItems tElectricCheckinItems : tElectricCheckinItemsList) {
			String tElectricCheckinItemsId = tElectricCheckinItems.getFid();
			if (StringUtil.isEmpty(tElectricCheckinItemsId)) {
				tElectricCheckinItems.setCheckinId(id);
			} else {
				tElectricCheckinItemsIdList.add(tElectricCheckinItemsId);
			}
		}
		if (CollectionUtil.isNotEmpty(tElectricCheckinItemsIdList)) {
			itElectricCheckinItemsService.remove(Wrappers.<TElectricCheckinItems>query().lambda()
					.notIn(TElectricCheckinItems::getFid, tElectricCheckinItemsIdList)
					.eq(TElectricCheckinItems::getCheckinId, id));
		}
		itElectricCheckinItemsService.saveOrUpdateBatch(tElectricCheckinItemsList);
		tElectricCheckinLog.setFid(id);
		TElectricCheckinLog original =  getById(id);
		String roomNum = tElectricCheckinLog.getRoomNumber();
		ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
		//入宿
		if(Objects.equals(original.getIsCheckout(), 1) && Objects.equals(tElectricCheckinLog.getIsCheckout(), 0)){
			//有床位
			if(valueOperations.get(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum)!=null){
				//床位大于1
				if((Integer)valueOperations.get(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum)>1){
					redisTemplate.opsForValue().decrement(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum);
					this.updateById(tElectricCheckinLog);
					return roomService.upDateUsedRoomByRoomNum(roomNum,1);
				}
				//等于1
				redisTemplate.delete(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum);
				this.updateById(tElectricCheckinLog);
				return roomService.upDateUsedRoomByRoomNum(roomNum,1);
			}
			//无床位
			return false;
		}
		//退宿
		if(Objects.equals(original.getIsCheckout(), 0) && Objects.equals(tElectricCheckinLog.getIsCheckout(), 1)){
			//有床位
			if(valueOperations.get(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum)!=null){
				redisTemplate.opsForValue().increment(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum);
				this.updateById(tElectricCheckinLog);
				return roomService.upDateUsedRoomByRoomNum(roomNum,-1);
			}
			//无床位
			redisTemplate.opsForValue().set(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum,1);
			this.updateById(tElectricCheckinLog);
			return roomService.upDateUsedRoomByRoomNum(roomNum,-1);
		}
		//没有改变入宿状态
		return this.updateById(tElectricCheckinLog);
	}
	/**
	 * Title: 批量删除入住登记
	 * @description 登记退宿对应房间入住人员减1
	 * @createTime  2023-07-25 11:09
	 * @param
	 * @return
	 */
	@Override
	@Transactional(rollbackFor=Exception.class)
	public boolean delete(String ids) {
		List<String> idList = Func.toStrList(ids);
		HashSet<String> newList = new HashSet<>();
		List<TDormitoryRoom> rooms = new ArrayList<>();
		ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
		//遍历idList拿到不重复的房间号码
		for(String id:idList){
			TElectricCheckinLog tElectricCheckinLog = getById(id);
			if(Objects.equals(tElectricCheckinLog.getIsCheckout(), 0)&&StringUtils.isNotBlank(tElectricCheckinLog.getRoomNumber())){
				newList.add(tElectricCheckinLog.getRoomNumber());
			}
		}
		//遍历newList中的房间，在idList的登记资料中美出现一次释放使用的床位
		for(String roomNum :newList){
			TDormitoryRoom room = roomService.getByRoomNumber(roomNum);
			for(String id :idList){
				TElectricCheckinLog checkinLog = getById(id);
				if(Objects.equals(checkinLog.getRoomNumber(), roomNum)){
					if(valueOperations.get(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum)!=null){
						redisTemplate.opsForValue().increment(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum);
					}
					else{
						redisTemplate.opsForValue().set(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum,1);
					}
					room.setUsedBedNumber(room.getUsedBedNumber()-1);
				}
			}
			rooms.add(room);
		}
		//删除和更新操作
		if (this.removeByIds(idList)) {
			itElectricCheckinItemsService.remove(Wrappers.<TElectricCheckinItems>query().lambda().in(TElectricCheckinItems::getCheckinId, ids));
			return roomService.updateBatchById(rooms);
		}
		return false;
	}

	@Override
	@Transactional(rollbackFor=Exception.class)
	public HashSet<String> branchImport(List<TElectricCheckinLog> tElectricCheckinLogs){
		HashSet<String> newList = new HashSet<>();
		List<TDormitoryRoom> rooms = new ArrayList<>();
		HashSet<String> badrooms = new HashSet<>();
		ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
		//遍历tElectricCheckinLogs拿到不重复的房间号码
		for (TElectricCheckinLog checkinLog:
			 tElectricCheckinLogs) {
			if(Objects.equals(checkinLog.getIsCheckout(), 0)&&StringUtils.isNotBlank(checkinLog.getRoomNumber())){
				newList.add(checkinLog.getRoomNumber());
			}
			if(checkinLog.getGender().equals("男")){
				checkinLog.setGender(1);
			}else{
				checkinLog.setGender(0);
			}
		}
		//遍历所有的房间，每有一个对应的人员入住就锁定一张床位
		if(!newList.isEmpty()){
			for(String roomNum :newList){
				TDormitoryRoom room = roomService.getByRoomNumber(roomNum);
				for(TElectricCheckinLog checkinLog :tElectricCheckinLogs){
					if(Objects.equals(checkinLog.getRoomNumber(), roomNum)){
						if(valueOperations.get(RedisKeyConstants.CACHE_ROOM_LEFT+roomNum)!=null){
							room.setUsedBedNumber(room.getUsedBedNumber()+1);
						}
						else{
							badrooms.add(roomNum);
						}
					}
				}
				rooms.add(room);
			}
			if(badrooms.isEmpty()){
				boolean b = roomService.updateBatchById(rooms) && this.saveBatch(tElectricCheckinLogs);
				return badrooms;
			}
		}
		return badrooms;
	}

	@Override
	public List<TElectricCheckinLog> checkinLogList(){
		return this.list(Wrappers.<TElectricCheckinLog>query().lambda().eq(TElectricCheckinLog::getIsCheckout,0));
	}

	@Override
	public List<TElectricCheckoutSettlementTools> getTElectricCheckinItemsByParentId(String parentId){
		Wrapper wrapper = Wrappers.<TElectricCheckinItems>query().lambda().eq(TElectricCheckinItems::getCheckinId, parentId);
		return itElectricCheckinItemsService.list(wrapper);
	}
}